package com.iagent.core.resolver;

import com.iagent.annotation.*;
import com.iagent.bean.IagentBeanWrapper;
import com.iagent.core.resolver.annotation.AnnotationResolver;
import com.iagent.factory.IagentConfiguration;
import com.iagent.logging.LogFactory;
import com.iagent.logging.Logger;
import com.iagent.plugins.PluginChain;
import com.iagent.request.AbstractHttpExecutor;
import com.iagent.request.HttpExecutor;
import com.iagent.request.RequestConfig;
import com.iagent.util.BeanUtils;
import com.iagent.util.ClassUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author liujieyu
 * @date 2022/5/27 21:19
 * @desciption
 */
public abstract class AbstractInterfaceAnnotationResolver implements InterfaceAnnotationResolver {

    private static final Logger logger = LogFactory.getLogger(AbstractInterfaceAnnotationResolver.class);

    private final IagentConfiguration configuration;

    private final PluginChain pluginChain = new PluginChain();

    /**
     * @see com.iagent.core.resolver.annotation.BodyAnnotationResolver
     * @see com.iagent.core.resolver.annotation.GenericAnnotationResolver
     * @see com.iagent.core.resolver.annotation.HeaderAnnotationResolver
     * @see com.iagent.core.resolver.annotation.PathKeyAnnotationResolver
     */
    private final String[] ANNOTATION_RESOLVER = new String[]{
            "com.iagent.core.resolver.annotation.BodyAnnotationResolver",
            "com.iagent.core.resolver.annotation.GenericAnnotationResolver",
            "com.iagent.core.resolver.annotation.HeaderAnnotationResolver",
            "com.iagent.core.resolver.annotation.PathKeyAnnotationResolver"
    };

    // 注解解析器
    private List<AnnotationResolver> resolverList = new ArrayList<>(ANNOTATION_RESOLVER.length);

    public AbstractInterfaceAnnotationResolver(IagentConfiguration configuration) {
        super();
        this.configuration = configuration;
        for (String className : ANNOTATION_RESOLVER) {
            resolverList.add(BeanUtils.instance(className, AnnotationResolver.class));
        }
    }

    @Override
    public boolean existsIagentAnnotation(Method method) {
        return method.getAnnotation(IagentUrl.class) != null || method.getAnnotation(GetUrl.class) != null ||
                method.getAnnotation(PostUrl.class) != null || method.getAnnotation(DeleteUrl.class) != null ||
                method.getAnnotation(PutUrl.class) != null;
    }

    /**
     * Generates an interceptor proxy instance and registers the specified actuator instance
     *
     * @param executorClass
     * @param httpExecutor
     */
    protected void registerHttpExecutor(Class<? extends HttpExecutor> executorClass, HttpExecutor httpExecutor) {
        this.configuration.getExecutorRegister().
                registerBean(ClassUtils.getClassPathByClass(executorClass),
                        (HttpExecutor) pluginChain.loadAllPlugins(configuration.getPlugins(), httpExecutor));
    }

    /**
     * 是否包含某个执行器
     * @param executorClass
     * @return
     */
    protected boolean containHttpExecutor(Class<? extends HttpExecutor> executorClass) {
        if (!AbstractHttpExecutor.class.isAssignableFrom(executorClass)) {
            logger.warn("The Http Executor is Not extends AbstractHttpExecutor!");
        }
        return this.configuration.getExecutorRegister()
                .containBeanName(ClassUtils.getClassPathByClass(executorClass));
    }

    /**
     * 获取指定执行器实例
     * @param executorClass
     * @return
     */
    protected HttpExecutor getHttpExecutor(Class<? extends HttpExecutor> executorClass) {
        return this.configuration.getExecutorRegister().getBeanObject(ClassUtils.getClassPathByClass(executorClass));
    }

    /**
     * 注册方法包装类
     * @param method
     * @param wrapper
     */
    protected void registerBeanWrapper(Method method, IagentBeanWrapper wrapper) {
        this.configuration.getBeanWrapperRegister().registerBean(String.valueOf(method.hashCode()), wrapper);
    }

    /**
     * get default config
     * @return
     */
    protected RequestConfig getDefaultRequestConfig() {
        return this.configuration.getDefaultRequestConfig();
    }

    protected IagentConfiguration getConfiguration() {
        return configuration;
    }

    protected List<AnnotationResolver> getParameterResolvers() {
        return resolverList;
    }

}
